/******************************************************************************* 
  Copyright (C), 1988-2020, zeno Tech. Co., Ltd.
  Description:   osd画线画框  
  Function List:     
  History: 
*******************************************************************************/ 
/*=============================================================================
                                 Includes                                  
 =============================================================================*/
#include "mediaPriv.h"

#include "StreamComposeMgr.h"

#include "AudioEncode.h"

#include "AudioInMgr.h"

#include "CurtainActManager.h"

/*=============================================================================
                               Macro Definition
 =============================================================================*/

#include "uvc.h"
/*=============================================================================
                        Local Structures and Typedef 
 =============================================================================*/ 


/*=============================================================================
                             Local Variables                                  
 =============================================================================*/  
static Media::AudioInMgr*  pUacAudioInput_s = nullptr;
static bool uacInCtl_s = false;
static uint8_t volumeFactor_s = 100;

/*=============================================================================
                             Function Definition                                  
 =============================================================================*/
/*******************************************************************************
* 函数名  : MEDIA_UvcStart
* 描  述  : 启动编码
* 输  入  : 无。
* 输  出  : 无。
* 返回值  : 0:  成功。
*           -1: 失败。
*******************************************************************************/
static int MEDIA_UvcStart(void)
{
    int status;

    status = mediaCtl_g.pVideoEncoder[USBTYPEC_OUT]->start(mediaCtl_g.pVideoEncoder[USBTYPEC_OUT]);
    if (status)
    {
        LOG_PrintInfo("Fail to start encoder!\n");
        return -1;
    }

    mediaCtl_g.uvcState = 1;

    //LOG_PrintWarn("MEDIA_UvcStart-----!!\n");

    Media::CurtainActManager::instance()->ctrlUsbVideo(true);
    
    return 0;
}

/*******************************************************************************
* 函数名  : MEDIA_UvcStop
* 描  述  : 停止编码
* 输  入  : 无。
* 输  出  : 无。
* 返回值  : 0:  成功。
*           -1: 失败。
*******************************************************************************/
static int MEDIA_UvcStop(void)
{
    int status;

    status = mediaCtl_g.pVideoEncoder[USBTYPEC_OUT]->stop(mediaCtl_g.pVideoEncoder[USBTYPEC_OUT]);
    if (status)
    {
        LOG_PrintInfo("Fail to start encoder!\n");
        return -1;
    }

    mediaCtl_g.uvcState = 0;

    //LOG_PrintWarn("MEDIA_UvcStop-----!!\n");

    Media::CurtainActManager::instance()->ctrlUsbVideo(false);
    
    return 0;
}

#define v4l2_fourcc(a, b, c, d) \
    ((unsigned int)(a) | ((unsigned int)(b) << 8) | ((unsigned int)(c) << 16) | ((unsigned int)(d) << 24))

#define V4L2_PIX_FMT_YUYV v4l2_fourcc('Y', 'U', 'Y', 'V')   /* 16  YUV 4:2:2     */
#define V4L2_PIX_FMT_YUV420 v4l2_fourcc('Y', 'U', '1', '2') /* 16  YUV 4:2:0     */
#define V4L2_PIX_FMT_MJPEG v4l2_fourcc('M', 'J', 'P', 'G')  /* Motion-JPEG   */
#define V4L2_PIX_FMT_H264 v4l2_fourcc('H', '2', '6', '4')   /* H264 with start codes */
#define V4L2_PIX_FMT_YVU420 v4l2_fourcc('Y','V','1','2')



static int MEDIA_UvcSetformat(struct encoder_property *pFmt)
{
    int status;
    VideoEncFormat encFormat;

    memset(&encFormat, 0, sizeof(VideoEncFormat));

    if (pFmt->format == V4L2_PIX_FMT_H264)
    {
        encFormat.type = videoEncH264;
    }
    else if (pFmt->format == V4L2_PIX_FMT_MJPEG)
    {
        encFormat.type = videoEncMotionJPEG;
    }
    else
    {
        encFormat.type = videoYuv420;
    }
    
    encFormat.width = pFmt->width;
    encFormat.height = pFmt->height;
    encFormat.bitrateControl = videoEncBitrateCtrlConstant;
    
    encFormat.fps = 30; //后续调整从配置读取
    encFormat.gop = encFormat.fps*2;
    encFormat.quality = 1;
    encFormat.qualityType = 0;
    encFormat.pack = videoEncPackTypeRAW;
    encFormat.profile = h264ProfileHigh;

    if (encFormat.type == videoEncMotionJPEG)
    {
        encFormat.bitrate = (1*encFormat.width*encFormat.height/1024)*encFormat.fps*5;       
    }
    else
    {
        if ((encFormat.width == 3840) && (encFormat.height == 2160))
        {
            encFormat.bitrate = (1*encFormat.width*encFormat.height/1024)*encFormat.fps/10;
        }
        else
        {
            encFormat.bitrate = (1*encFormat.width*encFormat.height/1024)*encFormat.fps/5;
        }
    }

    status = mediaCtl_g.pVideoEncoder[USBTYPEC_OUT]->setFormat(mediaCtl_g.pVideoEncoder[USBTYPEC_OUT], &encFormat);
    if (status)
    {
        LOG_PrintInfo("Fail to start encoder!\n");
        return -1;
    }
    
    return 0;
}


static int MEDIA_UvcSetIdr(void)
{
    int status;
    
    status = mediaCtl_g.pVideoEncoder[USBTYPEC_OUT]->forceIFrame(mediaCtl_g.pVideoEncoder[USBTYPEC_OUT]);
    if (status)
    {
        LOG_PrintInfo("Fail to start encoder!\n");
        return -1;
    }
    
    return 0;
}

#if 0
static int msSleep(long ms) {
   struct timeval tv;
   tv.tv_sec = 0;
   tv.tv_usec = ms;
   return select(0, NULL, NULL, NULL, &tv);
}
#endif

/*******************************************************************************
* 函数名  : MEDIA_UvcGetPacket
* 描  述  : 获取编码数据
* 输  入  : 无。
* 输  出  : - pPacket: 编码数据
* 返回值  : 0:  成功。
*           -1: 失败。
*******************************************************************************/
static int MEDIA_UvcGetPacket(UVC_vencPacket_t *pPacket)
{
    int status;
    VideoEncPacket encPacket;
    int len;
    VideoEncBuf	buffer;
    int dataLen;
    char *pData;

    /*len = mediaCtl_g.pVideoEncoder[USBTYPEC_OUT]->requestPacket(mediaCtl_g.pVideoEncoder[USBTYPEC_OUT]);
    if (len > 0)
    {
        buffer.buffer = (unsigned char *)mediaCtl_g.pEncBuf;
        buffer.len = len;
        encPacket.vBuffer = &buffer;
        encPacket.vSize = 1;
    }
    else
    {
        usleep(1*1000);
        return -1;
    }*/

    //buffer.buffer = (unsigned char *)mediaCtl_g.pEncBuf[mediaCtl_g.uvcChn];
    //buffer.len = len;
    encPacket.vBuffer = &buffer;
    encPacket.vSize = 1;

    status = mediaCtl_g.pVideoEncoder[USBTYPEC_OUT]->getPacket(mediaCtl_g.pVideoEncoder[USBTYPEC_OUT], 
                                                   &encPacket);
    if (status)
    {
        usleep(1*1000);
        //LOG_PrintError("Fail to get packet.\n");
        return -1;
    }

    pData = (char *)encPacket.vBuffer[0].buffer;
    dataLen = encPacket.vBuffer[0].len;

#if 0
    char streamFileName[32] = {0};
    char recordPath[128] = "./jpeg";
    FILE *pStreamFile = NULL;
    static int count = 0;
    
    if (!(count%30))
    {
        sprintf(streamFileName, "%s/encStream_%d.jpeg", recordPath, count);
        pStreamFile = fopen(streamFileName, "wb");
        if (!pStreamFile)
        {
            LOG_PrintError("open file failed!\n");
            return -1;
        }
        fwrite(pData, dataLen, 1, pStreamFile);
        fclose(pStreamFile);
    }

    count++;
    if (count > 270)
    {
        count = 271;
    }

    //fflush(pStreamFile);
    //fclose(pStreamFile);
#endif

    pPacket->pBuf = pData;
    pPacket->dataLen = dataLen;

    return 0;
}

/*******************************************************************************
* 函数名  : MEDIA_UvcReleasePacket
* 描  述  : 释放编码数据
* 输  入  : 无。
* 输  出  : 无。
* 返回值  : 0:  成功。
*           -1: 失败。
*******************************************************************************/
static int MEDIA_UvcReleasePacket(void)
{    
    mediaCtl_g.pVideoEncoder[USBTYPEC_OUT]->releasePacket(mediaCtl_g.pVideoEncoder[USBTYPEC_OUT]);
    
    return 0;
}

#if 0
static unsigned short MEDIA_UvcGetBrightness(void)
{
    return mediaCtl_g.cfg.videoColor.brightness;
}

static int MEDIA_UvcGetContrast(void)
{
    return mediaCtl_g.cfg.videoColor.contrast;
}

static int MEDIA_UvcGetSaturation(void)
{
    return mediaCtl_g.cfg.videoColor.saturation;
}

static int MEDIA_UvcGetHue(void)
{
    return mediaCtl_g.cfg.videoColor.hue;
}

static unsigned short MEDIA_UvcGetGain(void)
{
    return mediaCtl_g.cfg.inOptions.compansation;
}

static unsigned char MEDIA_UvcGetLineFreq(void)
{
    return mediaCtl_g.cfg.inOptions.antiFlicker;
}

static int MEDIA_UvcSetColor(VideoColor *pColor)
{
    int status;
    VideoInput *pVideoInput;

    pVideoInput = mediaCtl_g.pVideoInput;
    if (!pVideoInput)
    {
        LOG_PrintError("pVideoInput is NULL!\n");
        return -1;
    }

    status = pVideoInput->setColor(pVideoInput, pColor);
    if (status)
    {
        LOG_PrintError("Fail to get video color.\n");
        return -1;
    }
    
    return 0;
}

static int MEDIA_UvcSetBrightness(unsigned short value)
{
    int ret;
    char key[8] = {0};
    VideoColor viColor;

    memcpy(&viColor, &mediaCtl_g.cfg.videoColor, sizeof(VideoColor));

    viColor.brightness = value;
    ret = MEDIA_UvcSetColor(&viColor);
    if (ret)
    {
        return -1;
    }

    mediaCtl_g.cfg.videoColor.brightness = viColor.brightness;

    sprintf(key, "%d", viColor.brightness);
    ret = INI_KeySet(CONFIG_PATH, "ispColor", "brightness", key);
    if (ret)
    {
        return -1;
    }

    return 0;
}

static int MEDIA_UvcSetContrast(unsigned short value)
{
    int ret;
    char key[8] = {0};
    VideoColor viColor;

    memcpy(&viColor, &mediaCtl_g.cfg.videoColor, sizeof(VideoColor));

    viColor.contrast = value;
    ret = MEDIA_UvcSetColor(&viColor);
    if (ret)
    {
        return -1;
    }

    mediaCtl_g.cfg.videoColor.contrast = viColor.contrast;

    sprintf(key, "%d", viColor.contrast);
    ret = INI_KeySet(CONFIG_PATH, "ispColor", "contrast", key);
    if (ret)
    {
        return -1;
    }

    return 0;
}

static int MEDIA_UvcSetSaturation(unsigned short value)
{
    int ret;
    char key[8] = {0};
    VideoColor viColor;

    memcpy(&viColor, &mediaCtl_g.cfg.videoColor, sizeof(VideoColor));

    viColor.saturation = value;
    ret = MEDIA_UvcSetColor(&viColor);
    if (ret)
    {
        return -1;
    }

    mediaCtl_g.cfg.videoColor.saturation = viColor.saturation;

    sprintf(key, "%d", viColor.saturation);
    ret = INI_KeySet(CONFIG_PATH, "ispColor", "saturation", key);
    if (ret)
    {
        return -1;
    }

    return 0;
}

static int MEDIA_UvcSetHue(unsigned short value)
{
    int ret;
    char key[8] = {0};
    VideoColor viColor;

    memcpy(&viColor, &mediaCtl_g.cfg.videoColor, sizeof(VideoColor));

    viColor.hue = value;
    ret = MEDIA_UvcSetColor(&viColor);
    if (ret)
    {
        return -1;
    }

    mediaCtl_g.cfg.videoColor.hue = viColor.hue;

    sprintf(key, "%d", viColor.hue);
    ret = INI_KeySet(CONFIG_PATH, "ispColor", "hue", key);
    if (ret)
    {
        return -1;
    }

    return 0;
}

static int MEDIA_UvcGetBalanceMode(void)
{
    return (mediaCtl_g.cfg.inOptions.whiteBalance == whiteBalanceAuto) ? 1: 0;
}

static int MEDIA_UvcGetColorTemp(void)
{
    return mediaCtl_g.cfg.inOptions.colorTemp;
}

static int MEDIA_UvcSetOptions(VideoInOptions *pOptions)
{
    int status;
    VideoInput *pVideoInput;

    pVideoInput = mediaCtl_g.pVideoInput;
    if (!pVideoInput)
    {
        LOG_PrintError("pVideoInput is NULL!\n");
        return -1;
    }

    status = pVideoInput->setOptions(pVideoInput, pOptions);
    if (status)
    {
        LOG_PrintError("Fail to get options.\n");
        return -1;
    }
    
    return 0;
}

static int MEDIA_UvcSetTemperature(unsigned short value)
{
    int ret;
    char key[8] = {0};
    VideoInOptions options;

    memcpy(&options, &mediaCtl_g.cfg.inOptions, sizeof(VideoInOptions));

    options.colorTemp = value;
    options.whiteBalance = whiteBalanceManual;

    ret = MEDIA_UvcSetOptions(&options);
    if (ret)
    {
        return -1;
    }

    mediaCtl_g.cfg.inOptions.colorTemp = options.colorTemp;
    mediaCtl_g.cfg.inOptions.whiteBalance = options.whiteBalance;

    sprintf(key, "%d", options.colorTemp);
    ret = INI_KeySet(CONFIG_PATH, "whiteBalance", "colortemp", key);
    if (ret)
    {
        return -1;
    }

    sprintf(key, "%d", options.whiteBalance);
    ret = INI_KeySet(CONFIG_PATH, "whiteBalance", "mode", key);
    if (ret)
    {
        return -1;
    }

    return 0;
}

static int MEDIA_UvcSetBalanceMode(unsigned char value)
{
    int ret;
    char key[8] = {0};
    VideoInOptions options;

    memcpy(&options, &mediaCtl_g.cfg.inOptions, sizeof(VideoInOptions));

    if (1 == value)
    {
        options.whiteBalance = whiteBalanceAuto;
    }
    else
    {
        options.whiteBalance = whiteBalanceManual;
    }

    ret = MEDIA_UvcSetOptions(&options);
    if (ret)
    {
        return -1;
    }

    mediaCtl_g.cfg.inOptions.whiteBalance = options.whiteBalance;

    sprintf(key, "%d", options.whiteBalance);
    ret = INI_KeySet(CONFIG_PATH, "whiteBalance", "mode", key);
    if (ret)
    {
        return -1;
    }

    return 0;
}

static int MEDIA_UvcSetGain(unsigned short value)
{
    int ret;
    char key[8] = {0};
    VideoInOptions options;

    memcpy(&options, &mediaCtl_g.cfg.inOptions, sizeof(VideoInOptions));

    options.compansation = value;

    ret = MEDIA_UvcSetOptions(&options);
    if (ret)
    {
        return -1;
    }

    mediaCtl_g.cfg.inOptions.compansation = options.compansation;

    sprintf(key, "%d", options.compansation);
    ret = INI_KeySet(CONFIG_PATH, "exposure", "compensation", key);
    if (ret)
    {
        return -1;
    }

    return 0;
}

static int MEDIA_UvcSetLineFreq(unsigned char value)
{
    int ret;
    char key[8] = {0};
    VideoInOptions options;

    memcpy(&options, &mediaCtl_g.cfg.inOptions, sizeof(VideoInOptions));

    options.antiFlicker = value;

    ret = MEDIA_UvcSetOptions(&options);
    if (ret)
    {
        return -1;
    }

    mediaCtl_g.cfg.inOptions.antiFlicker = options.antiFlicker;

    sprintf(key, "%d", options.antiFlicker);
    ret = INI_KeySet(CUSTOM_PATH, "custom", "exposure_frequency", key);
    if (ret)
    {
        return -1;
    }

    return 0;
}

static int MEDIA_UvcGetZoomAbs(void)
{
	int zoomPos = 0;
	int val = 0;
	float tmpVal = 0;
	
	zoomPos = REMOTE_UvcGetZoomVal();
	
	if(zoomPos <= 782)//光学变倍
	{
		tmpVal = ((float)zoomPos*109/782) + 0.5 + 40;
		val = (int)tmpVal;
	}
	else if (zoomPos == 782+40)
	{
		val = 149;
	}
	else//数字变倍
	{//((val-150)*359/90+823)
		tmpVal = (((float)zoomPos - 823)*90/359) + 150 + 0.5;
		val = (int)tmpVal;
	}
	return val;
}

/*
 * 函数说明: 此接口用于UVC获取设备水平位置接口
 * 由于uvc设置值是以3600为步进的值，故对数据做3600对齐的操作
 */
static int MEDIA_UvcGetPanAbs(void)
{
	int val;
	int mark;

	val = REMOTE_UvcGetPanVal();
	val = (val-13900)*4320/278.00;
	mark = val/abs(val);
	val = abs(val);

	if((float)(((float)val/3600.00) - (val/3600)) > 0.5)
	{
		val = (val/3600 + 1) * 3600;
	}
	else
	{
		val = (val/3600) * 3600;
	}
	val = val * mark;
	val = -val;
    return val;
}

/*
 * 函数说明: 此接口用于UVC获取设备垂直位置接口
 * 由于uvc设置值是以3600为步进的值，故对数据做3600对齐的操作
 */
static int MEDIA_UvcGetTiltAbs(void)
{
	int val;
	int mark;

	val = REMOTE_UvcGetTiltVal();
	val = (val-700)*3240/14;
	mark = val/abs(val);
	val = abs(val);

	if ((val - (val/3600)*3600) > 0)
	{
		val = (val/3600 + 1) * 3600;
	}
	val = val * mark;
	val = -val;
    return val;
}

static int MEDIA_UvcCalcCropRect(int zoomAbs, int pan, int tilt, Rect_ext *pRect)
{
    pRect->w = ALIGN_DOWN((640*240)/zoomAbs, 2);
    pRect->h = ALIGN_DOWN((360*240)/zoomAbs, 2);
    pRect->x = (VI_WIDTH - pRect->w)/2;
    pRect->y = (VI_HEIGHT - pRect->h)/2;

    pRect->x += (pan*VI_WIDTH)/120;
    pRect->y -= (tilt*VI_HEIGHT)/90;

    if (pRect->x < 0)
    {
        pRect->x = 0;
    }

    if (pRect->y < 0)
    {
        pRect->y = 0;
    }

    if ((pRect->w+pRect->x) > VI_WIDTH)
    {
        pRect->x = VI_WIDTH - pRect->w;
    }

    if ((pRect->h+pRect->y) > VI_HEIGHT)
    {
        pRect->y = VI_HEIGHT - pRect->h;
    }
    
    return 0;
}

/*
 * 函数说明: uvc设置变倍接口
 * 参数
: short val: uvc设置的云台变倍值[40, 240],step:1
 * 其中：数字变倍部分极值[40， 400]，光学变倍部分极值[0, 782]
 * 取160为光学变倍和数字变倍分界点，其中数字变倍时需要给REMOTE_UvcSetZoomVal()传变参
 * 用于remote线程中判断是否zoomrun的依据
 */
static void MEDIA_UvcSetZoomAbs(short val)
{
    VideoEncoder *pVideoEncoder;

    pVideoEncoder = mediaCtl_g.pVideoEncoder[USBTYPEC_OUT];

    if ((mediaCtl_g.cfg.aiMode != 0) || (mediaCtl_g.cfg.speakTrackMode == 2))
    {
        pthread_mutex_lock(&mediaCtl_g.algMutex);
        pVideoEncoder->setScreenMode(pVideoEncoder, 0);
        mediaCtl_g.cfg.speakTrackMode = 0;
        mediaCtl_g.cfg.aiMode = 0;
        pthread_mutex_unlock(&mediaCtl_g.algMutex);
    }

	if((val >= 40) && (val <= 149))
	{
		REMOTE_UvcSetZoomVal((val-40)*782/109); //0~782//光学变倍用
	}
	else if(val >= 150)
	{
		REMOTE_UvcSetZoomVal((val-150)*359/90+823);//782+41~782+400//数字变倍用
	}

    return ;  
}

/*
 * 函数说明: uvc设置云台水平运动接口
 * 参数
: int val: uvc设置的云台水平运动方向的位置值[-21600, 21600],step:3600
 * 位置极值分别对应设备最左端，最右端。[0, 27800]
 */
static void MEDIA_UvcSetPanAbs(int val)
{
    VideoEncoder *pVideoEncoder;

    pVideoEncoder = mediaCtl_g.pVideoEncoder[USBTYPEC_OUT];

    if ((mediaCtl_g.cfg.aiMode != 0) || (mediaCtl_g.cfg.speakTrackMode == 2))
    {
        pthread_mutex_lock(&mediaCtl_g.algMutex);
        pVideoEncoder->setScreenMode(pVideoEncoder, 0);
        mediaCtl_g.cfg.speakTrackMode = 0;
        mediaCtl_g.cfg.aiMode = 0;
        pthread_mutex_unlock(&mediaCtl_g.algMutex);
    }
	
	val = -val;
	REMOTE_UvcSetPanVal(val*278/4320+13900);
	//LOG_PrintError("uvc panval %d\n", val*278/4320+13900);
	
    return ;
}

/*
 * 函数说明: uvc设置云台垂直运动接口
 * 参数
: int val: uvc设置的云台垂直运动方向的位置值[-16200, 16200],step:3600
 * 位置极值分别对应设备最上端，最下端。[1400, 0]
 */
static void MEDIA_UvcSetTiltAbs(int val)
{
    VideoEncoder *pVideoEncoder;
    pVideoEncoder = mediaCtl_g.pVideoEncoder[USBTYPEC_OUT];
    if ((mediaCtl_g.cfg.aiMode != 0) || (mediaCtl_g.cfg.speakTrackMode == 2))
    {
        pthread_mutex_lock(&mediaCtl_g.algMutex);
        pVideoEncoder->setScreenMode(pVideoEncoder, 0);
        mediaCtl_g.cfg.speakTrackMode = 0;
        mediaCtl_g.cfg.aiMode = 0;
        pthread_mutex_unlock(&mediaCtl_g.algMutex);
    }
	
	val = -val;
	REMOTE_UvcSetTiltVal(val*14/3240 + 700);

    return ;
}

static void MEDIA_UvcSetAiMode(unsigned char val)
{
    mediaCtl_g.cfg.aiMode = val;
}

static unsigned char MEDIA_UvcGetAiMode(void)
{
    return (unsigned char)mediaCtl_g.cfg.aiMode;
}


static void *MEDIA_UvcCropThd(void *parg)
{
    MEDIA_cfg_t *pCfg = (MEDIA_cfg_t *)parg;
    int zoomAbs = 40;
    int panAbs = 0;
    int tiltAbs = 0;
    VideoEncCropCfg encCropCfg;
    
    encCropCfg.enable = 1;
     
    while (1)
    {
        if ((zoomAbs != pCfg->zoomAbs) 
            || (panAbs != pCfg->panAbs)
            || (tiltAbs != pCfg->tiltAbs))
        {
            zoomAbs = pCfg->zoomAbs; 
            panAbs = pCfg->panAbs;
            tiltAbs = pCfg->tiltAbs;

            MEDIA_UvcCalcCropRect(zoomAbs, panAbs/3600, tiltAbs/3600, &encCropCfg.rect);
            //LOG_PrintWarn("x:%d,y:%d,w:%d,h:%d\n", encCropCfg.rect.x, encCropCfg.rect.y, encCropCfg.rect.w, encCropCfg.rect.h);
            mediaCtl_g.pVideoEncoder[USBTYPEC_OUT]->setEncodeCrop(mediaCtl_g.pVideoEncoder[USBTYPEC_OUT], &encCropCfg);
        }
        usleep(10*1000);
    }

    return NULL;
}

#endif

static int MEDIA_UacStart(void)
{
    return 0;
}


static int MEDIA_UacStop(void)
{
    return 0;
}


#if 1
static int MEDIA_UacGetPacket(UAC_aencPacket_t *pPacket)
{
    int ret;
    static char buf[MAX_PCM_SIZE] = {0};
    int length = 0;
    static int count = 0;

    memset(buf, 0, sizeof(buf));
  
    if(!Media::AudioEncode::instance(USBTYPEC_OUT)->getPacket(buf,  &length))
    {
        usleep(500);
        //printf("[%s][%d] [%s]\n",__FILE__,__LINE__,__FUNCTION__); 
        return -1;
    }

    if(mediaCtl_g.recordState == 0)
	{
		if(count < 2)
		{
			//发两帧数据给alsa，保证alsa开启后不发生underrun错误
			memset(pPacket->pBuf, 0, pPacket->dataLen);
			count ++;
		}
		else
		{
			return -1;
		}
	}
	else
	{
		count = 0;
	}

    pPacket->pBuf = buf;
    pPacket->dataLen = length;

    //media_FILE_Write("wyg/usbout.pcm", buf, length);
    //printf("MEDIA_UacGetPacket pPacket->dataLen=%d, PTS=%llu\n", pPacket->dataLen, pts);
    
    return 0;
}
#endif

static int MEDIA_UacReleasePacket(void)
{
    return 0;
}

static int MEDIA_UacGetStatus(void)
{
    return mediaCtl_g.isUacStop;
}

static int MEDIA_UacSetStatus(void)
{
    return mediaCtl_g.uacState = 0;
}

static int MEDIA_UacAoStart(void)
{
    int ret = 0;
    AudioEncFormat encFormat;
    memset(&encFormat, 0, sizeof(encFormat));
	encFormat.type = audioEncPCM;
    encFormat.pack = audioEncPackTypeRAW;
    encFormat.frequency = 16000;
    encFormat.channelNum = 1;
    encFormat.depth = 16;
 
    if(!Media::AudioEncode::instance(USBTYPEC_OUT)->setFormat(&encFormat))
    {
        LOG_PrintError("AencSetFormat failed\n"); 
        return -1;
    }
    
    if(!Media::AudioEncode::instance(USBTYPEC_OUT)->start())
    {
        LOG_PrintError("AencStart failed\n"); 
        return -1;
    }

    LOG_PrintInfo("MEDIA_UacAoStart success!\n");
    
    return 0;
}

static int MEDIA_UacAoStop(void)
{    
    if(!Media::AudioEncode::instance(USBTYPEC_OUT)->stop())
    {
        return -1;
    }

    LOG_PrintInfo("MEDIA_UacAoStop success\n"); 
    return 0;
}

static int MEDIA_UacAoSetVol(int volume)
{
    return 0;
}

static int MEDIA_UacGetAudioInStatus(void)
{
    PlayState state;
    getCurtainPlayState(&state);

    if(state == RUNNING)

    {
        return 0;
    }

    return -1;  
}

int MEDIA_UacVolumeFactorSet(int value)
{
    volumeFactor_s = value;

    LOG_PrintWarn("MEDIA_UacVolumeFactorSet volumeFactor_s:%d\n",volumeFactor_s);
    return 0;
}
 
static int MEDIA_UacVolumeConvert(short* audioData, int dataLen)
{
    if(!audioData || dataLen <= 0)
    {
        return -1;
    }
    
    for(int i = 0; i < dataLen / 2; ++i)
    {        
        audioData[i] = audioData[i] * volumeFactor_s / 100;
    }

    return 0;
}


static int MEDIA_UacPutPacket(UAC_aencPacket_t *pPacket)
{
    //LOG_PrintInfo("MEDIA_UacPutPacket success, length:%d!\n", pPacket->dataLen);
    
    if(uacInCtl_s && pUacAudioInput_s)
    {
        AudioInPacket packet;
        packet.buffer = pPacket->pBuf;
        packet.length = pPacket->dataLen;

        MEDIA_UacVolumeConvert((short*)packet.buffer, packet.length); //音量控制

        if(pUacAudioInput_s->putPacket(&packet))
        {
            return 0;
        }
    }
    
    return -1;
}


int MEDIA_UacInStart(int channel)
{
    pUacAudioInput_s = Media::AudioInMgr::instance(channel); 

    if(!pUacAudioInput_s)
    {
        LOG_PrintError("pUacAudioInput_s is NULL\n"); 
        return -1;
    }

    ///creat object
    AudioInDesc inDesc = {0};
    inDesc.card = 0;
    inDesc.channel = channel;
    if(!pUacAudioInput_s->createAudioIn(inDesc))
    {
        LOG_PrintError("pUacAudioInput_s->createAudioIn failed\n"); 
        return -1;
    }

    ///setformat
    AudioInAttr format = {0};
    format.enSampleFormat = SAMPLE_FMT_S16;               	
    format.enAiLayout = AI_NORMAL;
    format.source = EXTERNAL_IN_TYPE;
    format.u32SampleRate = 48000;
    format.u32Channels = 1;
    if(!pUacAudioInput_s->setFormat(format))
    {
        LOG_PrintError("pUacAudioInput_s->setFormat failed\n"); 
        return -1;
    }

    uacInCtl_s = true;

    LOG_PrintInfo("MEDIA_UacInStart success, channel:%d!\n", channel);

    return 0;
}

int MEDIA_UacInStop(void)
{
    uacInCtl_s = false;
    return 0;
}


/*******************************************************************************
* 函数名  : MEDIA_UvcInit
* 描  述  : 初始化UVC。
* 输  入  : 无。
* 输  出  : 无。
* 返回值  : 0:  成功。
*           -1: 失败。
*******************************************************************************/
int MEDIA_UvcInit(void)
{
    int status;
    //int ret;
    UVC_initParam_t initParam;
    //pthread_t cropThd;

    memset(&initParam, 0, sizeof(initParam));

    initParam.streamOps.startup = MEDIA_UvcStart;
    initParam.streamOps.shutdown = MEDIA_UvcStop;
    initParam.streamOps.get_packet = MEDIA_UvcGetPacket;
    initParam.streamOps.release_packet = MEDIA_UvcReleasePacket;
    initParam.streamOps.set_property = MEDIA_UvcSetformat;
    initParam.streamOps.set_idr = MEDIA_UvcSetIdr;
    
#if 0
    initParam.processingOps.brightness_get = MEDIA_UvcGetBrightness;
    initParam.processingOps.contrast_get = MEDIA_UvcGetContrast;
    initParam.processingOps.hue_get = MEDIA_UvcGetHue;
    initParam.processingOps.saturation_get = MEDIA_UvcGetSaturation;
    initParam.processingOps.power_line_frequency_get = MEDIA_UvcGetLineFreq;
    initParam.processingOps.white_balance_temperature_auto_get = MEDIA_UvcGetBalanceMode;
    initParam.processingOps.white_balance_temperature_get = MEDIA_UvcGetColorTemp;
    initParam.processingOps.gain_get = MEDIA_UvcGetBrightness;//MEDIA_UvcGetGain;

    initParam.processingOps.brightness_set = MEDIA_UvcSetBrightness;
    initParam.processingOps.contrast_set = MEDIA_UvcSetContrast;
    initParam.processingOps.hue_set = MEDIA_UvcSetHue;
    initParam.processingOps.saturation_set = MEDIA_UvcSetSaturation;
    initParam.processingOps.white_balance_temperature_auto_set = MEDIA_UvcSetBalanceMode;
    initParam.processingOps.white_balance_temperature_set = MEDIA_UvcSetTemperature;
    initParam.processingOps.gain_set = MEDIA_UvcSetBrightness;//MEDIA_UvcSetGain;
    initParam.processingOps.power_line_frequency_set = MEDIA_UvcSetLineFreq;

    initParam.inputOps.zoom_absolute_get = MEDIA_UvcGetZoomAbs;
    initParam.inputOps.pan_absolute_get = MEDIA_UvcGetPanAbs;
    initParam.inputOps.tilt_absolute_get = MEDIA_UvcGetTiltAbs;
    initParam.inputOps.zoom_absolute_set = MEDIA_UvcSetZoomAbs;
    initParam.inputOps.pan_absolute_set = MEDIA_UvcSetPanAbs;
    initParam.inputOps.tilt_absolute_set = MEDIA_UvcSetTiltAbs;

    initParam.extensionOps.ai_mode_get = MEDIA_UvcGetAiMode;
    initParam.extensionOps.ai_mode_set = MEDIA_UvcSetAiMode;
#endif

    initParam.audioOps.startup = MEDIA_UacStart;
    initParam.audioOps.shutdown = MEDIA_UacStop;
    initParam.audioOps.get_packet = MEDIA_UacGetPacket;
    initParam.audioOps.release_packet = MEDIA_UacReleasePacket;
    initParam.audioOps.get_status = MEDIA_UacGetStatus;
    initParam.audioOps.set_status = MEDIA_UacSetStatus;
    initParam.audioOps.aoStart = MEDIA_UacAoStart;
    initParam.audioOps.aoStop = MEDIA_UacAoStop;
    initParam.audioOps.aoPutPacket = MEDIA_UacPutPacket;
    initParam.audioOps.aoSetVol = MEDIA_UacAoSetVol;
    
    initParam.supportAudio = mediaCtl_g.cfg.audioInState;

    initParam.customOps.getAudioInStatus = MEDIA_UacGetAudioInStatus;
    
    status = UVC_Init(&initParam);
    if (status)
    {
        LOG_PrintInfo("Fail to init uvc server!\n");
        return -1;
    }

    /*ret = pthread_create(&cropThd, 0, MEDIA_UvcCropThd, &mediaCtl_g.cfg);
    if (ret)
    {
        LOG_PrintError("can't create thread: %s\n", strerror(ret));
        return -1;
    }*/

    return 0;
}


